package com.ys.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ys.common.R;
import com.ys.constant.ShopCode;
import com.ys.entity.MQEntity;
import com.ys.feign.CouponApi;
import com.ys.mapper.OrderMapper;
import com.ys.exception.CastException;
import com.ys.feign.GoodsApi;
import com.ys.feign.UserApi;
import com.ys.pojo.*;
import com.ys.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;



@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, TradeOrder> implements OrderService {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Value("${mq.order.topic}")
    private String topic;
    @Value("${mq.order.tag.cancel}")
    private String tag;


    @Override
    public R confirmOrder(TradeOrder order) {
        //1.校验订单
        checkOrder(order);

        //2.生成预订单
        savePreOrder(order);
        try {
            //3.扣减库存
            reduceGoodsNum(order);
            //4.扣减优惠券
            changeCoponStatus(order);

            //5.使用余额
            reduceMoneyPaid(order);
            //6.确认订单
            updateOrderStatus(order);
            //7.返回成功状态
            log.info("订单:["+order.getOrderId()+"]确认成功");
            int i = 1/0;
            return R.ok().success(ShopCode.SHOP_SUCCESS.getSuccess());

        } catch (Exception e) {
            //1.确认订单失败,发送消息
            System.out.println("捕获异常，发送信息");
            //封装数据的对象
            MQEntity mqEntity = new MQEntity();
            mqEntity.setOrderId(order.getOrderId());
            mqEntity.setCouponId(order.getCouponId());
            mqEntity.setGoodsId(order.getGoodsId());
            mqEntity.setGoodsNum(order.getGoodsNumber());
            mqEntity.setUserId(order.getUserId());
            mqEntity.setUserMoney(order.getMoneyPaid());
            System.out.println("消息对象"+mqEntity);

            try {
                //发送失败补偿的消息
                sendCancelOrderMessage(topic,
                        tag,
                        mqEntity.getOrderId().toString(),
                        JSON.toJSONString(mqEntity));
            } catch (MQBrokerException ex) {
                ex.printStackTrace();
            } catch (RemotingException ex) {
                ex.printStackTrace();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } catch (MQClientException ex) {
                ex.printStackTrace();
            }

            //2.返回失败状态
        }
        return R.error().success(ShopCode.SHOP_FAIL.getSuccess());
    }


    @Autowired
    private GoodsApi goodsApi;
    @Autowired
    private UserApi userApi;
    private void checkOrder(TradeOrder order) {
        System.out.println(order);
        //校验订单是否存在
        if(order==null){
            CastException.cast(ShopCode.SHOP_ORDER_INVALID);
        }
        //校验订单中的商品是否存在
        R goodsById = goodsApi.findGoodsById(order);
        HashMap<Object,Object> goodsmap = (HashMap<java.lang.Object, java.lang.Object>)goodsById.getData();
        System.out.println(goodsmap);
        TradeGoods goods = JSONObject.parseObject(JSON.toJSONString(goodsmap.get("goods")), TradeGoods.class);
        System.out.println(goods);
        if(goods==null){
            CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);
        }
        //校验下单用户是否存在
        R userById = userApi.findUserById(order);
        Map<Object, Object> usermap = userById.getData();
        TradeUser user = JSONObject.parseObject(JSON.toJSONString(usermap.get("user")), TradeUser.class);
        System.out.println(user);
        if(user==null){
            CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
        }
        //校验商品单价是否合法
        if(order.getGoodsPrice().compareTo(goods.getGoodsPrice())!=0){
            CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);
        }
        //校验订单商品数量是否合法
        if(order.getGoodsNumber()>=goods.getGoodsNumber()){
            CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        }
        System.out.println("校验通过");
        log.info("校验通过");
    }

    @Autowired
    private CouponApi couponApi;
    private Long savePreOrder(TradeOrder order){
        //设置订单状态为不可见
        order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());
        /*//生成订单ID
        order.setOrderId(2L);*/
        //核算运费是否正确
        BigDecimal shippingFee = BigDecimal.ZERO;//此处让运费为0
        //计算订单总价格是否正确
        //商品单价*商品数量
        BigDecimal orderAmount = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));
        //加上物流费用
        orderAmount.add(shippingFee);
        if(orderAmount.compareTo(order.getOrderAmount())!=0){
            CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);
        }
        //判断优惠券信息是否合法
        Long couponId = order.getCouponId();
        System.out.println(couponId);
        if (couponId!=null){
            R r = couponApi.findCouponById(couponId);
            Map<Object, Object> couponmap = r.getData();
            TradeCoupon coupon = JSONObject.parseObject(JSON.toJSONString(couponmap.get("coupon")), TradeCoupon.class);
            System.out.println(coupon);
            if (coupon==null){
                CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);
            }
            if((ShopCode.SHOP_COUPON_ISUSED.getCode().toString()).equals(coupon.getIsUsed().toString())){
                CastException.cast(ShopCode.SHOP_COUPON_INVALIED);
            }
            order.setCouponPaid(coupon.getCouponPrice());
        } else {
            order.setCouponPaid(BigDecimal.ZERO);
        }
        //判断余额是否正确
        BigDecimal moneyPaid = order.getMoneyPaid();
        if (moneyPaid!=null){
            int r = moneyPaid.compareTo(BigDecimal.ZERO);//订单金额只能>0
            if(r<0){
                CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);//订单金额小于0
            }
            if(r>0){
                R userById = userApi.findUserById(order);
                Map<Object, Object> usermap = userById.getData();
                System.out.println(usermap);
                TradeUser user = JSONObject.parseObject(JSON.toJSONString(usermap.get("user")), TradeUser.class);
                System.out.println(user);
                if(user==null){
                    CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
                }
                if (user.getUserMoney().compareTo(order.getMoneyPaid()) <0){
                    CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);//用户的余额小于订单金额
                }
                order.setMoneyPaid(order.getMoneyPaid());//看不懂？
            }
        } else {
            order.setMoneyPaid(BigDecimal.ZERO);
        }
        //计算订单支付总金额
       /* orderAmount.subtract(order.getCouponPaid())//减去优惠券金额
                        .subtract(order.getMoneyPaid());//减去商品余额*/
        order.setPayAmount(orderAmount.subtract(order.getCouponPaid())
                .subtract(order.getMoneyPaid()));
        //设置订单添加时间
        order.setAddTime(new Date());

        //保存预订单
        //orderMapper.insert(order);
        boolean save = this.save(order);

        if (save == false){
            CastException.cast(ShopCode.SHOP_ORDER_SAVE_ERROR);
        }
        log.info("订单:["+order.getOrderId()+"]预订单生成成功");
        System.out.println("预订单生成成功");
        return order.getOrderId();
    }

    private void reduceGoodsNum(TradeOrder order) {
        TradeGoodsNumberLog goodsNumberLog = new TradeGoodsNumberLog();
        goodsNumberLog.setGoodsId(order.getGoodsId());
        goodsNumberLog.setOrderId(order.getOrderId());
        goodsNumberLog.setGoodsNumber(order.getGoodsNumber());
        R result = goodsApi.reduceGoodsNum(goodsNumberLog);
        if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())) {
            CastException.cast(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);
        }
        log.info("订单:["+order.getOrderId()+"]扣减库存["+order.getGoodsNumber()+"个]成功");
    }

    private void changeCoponStatus(TradeOrder order) {
        //判断是否使用优惠券
        if(!StringUtils.isEmpty(order.getCouponId().toString())){
            //封装优惠券对象
            R couponById = couponApi.findCouponById(order.getCouponId());
            Map<Object, Object> data = couponById.getData();
            TradeCoupon coupon = JSONObject.parseObject(JSONObject.toJSONString(data.get("coupon")), TradeCoupon.class);
            coupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());
            coupon.setUsedTime(new Date());
            coupon.setOrderId(order.getOrderId());
            R r = couponApi.changeCoponStatus(coupon);
            //判断执行结果
            if (r.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){
                //优惠券使用失败
                CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);
            }
            log.info("订单:["+order.getOrderId()+"]使用扣减优惠券["+coupon.getCouponPrice()+"元]成功");
        }
    }

    private void reduceMoneyPaid(TradeOrder order) {
        //判断订单中使用的余额是否合法
        if (order.getMoneyPaid() != null && order.getMoneyPaid().compareTo(BigDecimal.ZERO) == 1) {
            TradeUserMoneyLog userMoneyLog = new TradeUserMoneyLog();
            userMoneyLog.setOrderId(order.getOrderId());
            userMoneyLog.setUserId(order.getUserId());
            userMoneyLog.setUseMoney(order.getMoneyPaid());
            userMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_PAID.getCode());

            R r = userApi.changeUserMoney(userMoneyLog);

            if (r.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){

                CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);
            }

            log.info("订单:["+order.getOrderId()+"扣减余额["+order.getMoneyPaid()+"元]成功]");
        }
    }

    private void updateOrderStatus(TradeOrder order) {

        order.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.getCode());
        order.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());
        order.setConfirmTime(new Date());

        boolean b = this.updateById(order);

        if (b==false){
            CastException.cast(ShopCode.SHOP_ORDER_CONFIRM_FAIL);
        }

        log.info("订单:["+order.getOrderId()+"]状态修改成功");
    }

    //发送订单确认失败消息  消费者接收到消息后 把之前下单修改的数据恢复
    //商品服务  回退库存
    //优惠券服务 更改优惠券状态
    // 用户服务 恢复余额
    // 订单服务 把订单的状态改为 已取消
    private void sendCancelOrderMessage(String topic, String tag, String keys, String body) throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
        //判断Topic是否为空
        if (org.springframework.util.StringUtils.isEmpty(topic)) {
            CastException.cast(ShopCode.SHOP_MQ_TOPIC_IS_EMPTY);
        }
        //判断消息内容是否为空
        if (org.springframework.util.StringUtils.isEmpty(body)) {
            CastException.cast(ShopCode.SHOP_MQ_MESSAGE_BODY_IS_EMPTY);
        }
        //消息体
        Message message = new Message(topic, tag, keys, body.getBytes());
        //发送消息
        rocketMQTemplate.getProducer().send(message);
    }

}
